package org.roguelikedevelopment.dweller.j2me;

import java.io.IOException;

import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;

import org.roguelikedevelopment.dweller.common.application.DwellerGraphics;

public class DwellerJ2MEGraphics implements DwellerGraphics {
	
	// the original size of the tiles in the PNGs
	public final byte ORIGINAL_TILE_SIZE = 8;
	
	// display width in pixels
	public int CANVAS_WIDTH;
	// display height in pixels
	public int CANVAS_HEIGHT;
	
	// scaled size of tiles
	public byte TILE_SIZE = 16;
	public int TILES_PER_ROW;
	public int TILES_PER_COLUMN;

	private Graphics graphics;

	private static boolean usesgraphics = true;

	private Image entities;
	private Image dungeon;
	private Image mask;
	private Image cursor;
	
	private DwellerJ2MECanvas canvas;

	public DwellerJ2MEGraphics(DwellerJ2MECanvas canvas) {
		this.canvas = canvas;
		useNormalTiles();
		loadGraphics();		
		updateSize();
	}
	
	public void updateSize() {
		CANVAS_WIDTH = canvas.getWidth();
		CANVAS_HEIGHT = canvas.getHeight();
		TILES_PER_ROW = 1 + CANVAS_WIDTH / TILE_SIZE;
		TILES_PER_COLUMN = 1 + CANVAS_HEIGHT / TILE_SIZE;
	}
	
	/**
	 * Checks if the canvas is using graphics tiles
	 * @return true if graphics tiles are used, otherwise false
	 */
	public boolean isUsingGraphics() {
		return usesgraphics;
	}
	
	/**
	 * Checks if the canvas is using normal size tiles
	 * @return true if normal size tiles are used, otherwise false
	 */
	public boolean isUsingNormalTiles() {
		return TILE_SIZE == ORIGINAL_TILE_SIZE;
	}
	

	/**
	 * Tells the canvas to use a normal size version of tiles
	 * Reloads tiles and recalculates screen dimensions
	 */
	public void useNormalTiles() {
		if(TILE_SIZE == ORIGINAL_TILE_SIZE) {
			return;
		}
		TILE_SIZE = ORIGINAL_TILE_SIZE;
		if(usesgraphics) {
			loadGraphics();
		}
		else {
			loadASCII();
		}
		updateSize();
	}

	/**
	 * Tells the canvas to use a large version of tiles
	 * Reloads tiles and recalculates screen dimensions
	 */
	public void useLargeTiles() {
		if(TILE_SIZE != ORIGINAL_TILE_SIZE) {
			return;
		}
		TILE_SIZE = ORIGINAL_TILE_SIZE * 2;
		if(usesgraphics) {
			loadGraphics();
		}
		else {
			loadASCII();
		}
		updateSize();
	}

	/**
	 * Loads graphical tiles
	 */
	public void loadGraphics() {
		usesgraphics = true;
		entities = loadImage("/entities_g.png", TILE_SIZE / ORIGINAL_TILE_SIZE);
		dungeon = loadImage("/dungeon_g.png", TILE_SIZE / ORIGINAL_TILE_SIZE);
		mask = loadImage("/mask.png", TILE_SIZE / ORIGINAL_TILE_SIZE);
		cursor = loadImage("/cursor.png", TILE_SIZE / ORIGINAL_TILE_SIZE);
	}
	
	/**
	 * Loads ascii tiles
	 */
	public void loadASCII() {
		usesgraphics = false;
		entities = loadImage("/entities_t.png", TILE_SIZE / ORIGINAL_TILE_SIZE);
		dungeon = loadImage("/dungeon_t.png", TILE_SIZE / ORIGINAL_TILE_SIZE);
		mask = loadImage("/mask.png", TILE_SIZE / ORIGINAL_TILE_SIZE);
		cursor = loadImage("/cursor.png", TILE_SIZE / ORIGINAL_TILE_SIZE);
	}
	
	private int[] reescalaArray(int[] ini, int x, int y, int x2, int y2) {  
		int out[] = new int[x2 * y2];  
		for (int yy = 0; yy < y2; yy++) {  
			int dy = yy * y / y2;  
			for (int xx = 0; xx < x2; xx++) {  
				int dx = xx * x / x2;  
				out[(x2 * yy) + xx] = ini[(x * dy) + dx];  
			}  
		}  
		return out;  
	}
	
	/**
	 * Loads an image
	 * @param filename Filename of the image to load
	 * @param scale Scale of the loaded image. The loaded image's width and height is multiplied with the scale
	 * @return The loaded image
	 */
	public Image loadImage(String filename, int scale) {
		Image source;
		try {
			source = Image.createImage(filename);
		}
		catch (IOException e) {
			e.printStackTrace();
			return null;
		}
		
		if(scale == 1) {
			return source;
		}
		
		int sourceWidth = source.getWidth();
		int sourceHeight = source.getHeight();
		int destWidth = sourceWidth * scale;
		int destHeight = sourceHeight * scale;
		
		int sourcergb[] = new int[sourceWidth * sourceHeight];  
		source.getRGB(sourcergb, 0, sourceWidth, 0, 0, sourceWidth, sourceHeight);  
		int destrgb[] = reescalaArray(sourcergb, sourceWidth, sourceHeight, destWidth, destHeight);  
		Image dest = Image.createRGBImage(destrgb, destWidth, destHeight, true); 
		return dest;
	}
	
	public void setGraphics(Graphics graphics) {
		this.graphics = graphics;
	}

	public final void clearTile(int x, int y) {
		graphics.setColor(0x000000);
		graphics.fillRect(x, y, TILE_SIZE, TILE_SIZE);
	}

	public final void drawCursor(int x, int y) {
		drawTile(cursor, 0, x, y);
	}
	
	public final void drawEntity(int tileindex, int x, int y) {
		drawTile(entities, tileindex, x, y);
	}
	
	public final void drawDungeon(int tileindex, int x, int y) {
		drawTile(dungeon, tileindex, x, y);
	}
	
	public final void drawFogOfWarMask(int x, int y) {
		drawTile(mask, 0, x, y);
	}
	
	private final void drawTile(Image tiles, int tileindex, int screenX, int screenY) {
		graphics.setClip(screenX, screenY, TILE_SIZE, TILE_SIZE);	
		int imageX = (tileindex % 16) * TILE_SIZE;
		int imageY = (tileindex / 16) * TILE_SIZE;                                        
		graphics.drawImage(tiles, screenX - imageX, screenY - imageY, Graphics.TOP | Graphics.LEFT);
		graphics.setClip(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
	}

	public int getTilesPerRow() {
		return TILES_PER_ROW;
	}

	public int getTilesPerColumn() {
		return TILES_PER_COLUMN;
	}

	public void drawLine(int rgb, int x1, int y1, int x2, int y2) {
		graphics.setColor(rgb);
		graphics.drawLine(x1, y1, x2, y2);
	}

	public void drawRect(int rgb, int x, int y, int width, int height) {
		graphics.setColor(rgb);
		graphics.drawRect(x, y, width, height);
	}

	public void fillRect(int rgb, int x, int y, int width, int height) {
		graphics.setColor(rgb);
		graphics.fillRect(x, y, width, height);
	}
	
	public void setClip(int x, int y, int width, int height) {
		graphics.setClip(x, y, width, height);
	}
	
	public void drawString(String str, int rgb, int x, int y) {
		graphics.setColor(rgb);
		graphics.drawString(str, x, y, Graphics.TOP | Graphics.LEFT);
	}

	public int getTileHeight() {
		return TILE_SIZE;
	}

	public int getTileWidth() {
		return TILE_SIZE;
	}
}
